package com.example.shopping.controller;

import cn.hutool.json.JSONUtil;
import com.example.shopping.dto.Result;
import com.example.shopping.security.LoginUserDetails;
import com.example.shopping.util.JwtUtils;
import com.example.shopping.util.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 功能：
 * 作者：张赛特
 * 日期：2025/11/18 9:30
 */
@RestController
public class LoginController {
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private RedisClient redisClient;
    /**
     * 登录
     * @param phone    手机号
     * @param password 密码
     * @return 响应结果
     */
    @PostMapping(value = "/login")
    public Result login(String phone,String password,HttpServletRequest request){

        //判断曾经登录是否还在有效期
        String token_=request.getHeader("token");
        if (StringUtils.hasText(token_)){
            String claim=JwtUtils.getClaim(token_);
            if (StringUtils.hasText(claim)&&claim.equals(phone)){
                String key="login:token:"+token_;
                redisClient.del(key);
            }
        }


        /*
         * SpringSecurity 的认证逻辑
         * 默认情况SpringSecurity内置了登录页面,内置了从页面获取数据,并将其数据送到SpringSecurity上下文的方式
         * 当前前后端分离的逻辑，数据不再从页面获取，所以不能再使用内置逻辑，需要程序员自己实现将数据送到SpringSecurity上下文中
         * 官网地址: https://docs.spring.io/spring-security/reference/5.8/servlet/authentication/passwords/form.html
         */
        //封装用户名(手机号作为用户名)和密码
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phone,password);
        //调用认证管理中的认证方法，调用后可能出现异常，所以需要try...catch
        try {
            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
            //如果认证成功Authentication中就会有用户信息,否则为空
            if(Objects.isNull(authenticate)){
                //认证失败
                return Result.error("认证失败,用户名或密码错误");
            }
            //登录成功将用户信息保存到redis中,以token作为key
            LoginUserDetails principal = (LoginUserDetails) authenticate.getPrincipal();
            if(Objects.isNull(principal)){
                return Result.error("认证失败,用户名或密码错误");
            }
            //将用户信息json化
            String json = JSONUtil.toJsonStr(principal);
            //使用token作为redis的key 格式为 login:token
            String token = JwtUtils.sign(principal.getUsername(), 1000 * 60 * 60 * 24 * 7L);//过期时间为7天
            //将用户信息json化后保存到redis中
            redisClient.set("login:token:"+token,json,1000*60 * 60 * 24 * 7L); //过期时间7天
            Map<String,Object> map = new HashMap<>();
            map.put("token",token);
            return Result.ok(map);
        }catch (RuntimeException e){
            e.printStackTrace();
            //认证失败
            return Result.error("认证失败,用户名或密码错误");
        }
    }
}
